/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.power.powercash;

import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
import com.db4o.ObjectServer;
import com.db4o.config.EmbeddedConfiguration;
import com.db4o.cs.Db4oClientServer;
import com.db4o.cs.config.ClientConfiguration;
import com.db4o.cs.config.ServerConfiguration;
import com.thoughtworks.xstream.XStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 *
 * @author Juno Roesler
 */
public class Configuration
{

  private String dbFile;

  private int port;

  private String host;

  private EmbeddedConfiguration econf;

  private ClientConfiguration conf;

  private ServerConfiguration sconf;

  public static int DEFAULT_DEPTH = 4;

  public static final int DEFAULT_PORT = 10001;

  private Map<String, String> users;

  private static ObjectContainer db = null;


  public Configuration()
  {
    dbFile = null;
    port = Configuration.DEFAULT_PORT;
    host = "localhost";
    econf = Db4oEmbedded.newConfiguration();
    conf = Db4oClientServer.newClientConfiguration();
    sconf = Db4oClientServer.newServerConfiguration();
    this.configure();
    users = new LinkedHashMap<String, String>();
  }

  @Override
  public Configuration clone()
  {
    Configuration c = new Configuration();
    c.setDBFile(dbFile);
    c.setHost(host);
    c.setPort(port);
    c.setServerConfiguration(sconf);
    c.setClientConfiguration(conf);
    c.setEmbeddedConfiguration(econf);
    Iterator<String> it = users.keySet().iterator();
    while(it.hasNext())
    {
      String user = it.next();
      String passwd = users.get(user);
      c.addUser(user, passwd);
    }
    return c;
  }

  public static ObjectContainer getDB()
  {
    return db;
  }

  public void configure()
  {
    econf.common().activationDepth(Configuration.DEFAULT_DEPTH);
    econf.common().updateDepth(Configuration.DEFAULT_DEPTH);
    conf.common().activationDepth(Configuration.DEFAULT_DEPTH);
    conf.common().updateDepth(Configuration.DEFAULT_DEPTH);
    sconf.common().activationDepth(Configuration.DEFAULT_DEPTH);
    sconf.common().updateDepth(Configuration.DEFAULT_DEPTH);
  }

  public void addUser(String user, String password)
  {
    users.put(user, password);
  }

  public String removeUser(String user)
  {
    return users.remove(user);
  }

  public void clearUsers()
  {
    users.clear();
  }

  public boolean containsUser(String user)
  {
    return users.containsKey(user);
  }

  public String getPassword(String user)
  {
    return users.get(user);
  }

  public int numUsers()
  {
    return users.size();
  }

  public static Configuration load(File f)
  {
    if(f == null)
      return null;

    XStream x = new XStream();
    x.omitField(Configuration.class, "econf");
    x.omitField(Configuration.class, "conf");
    x.omitField(Configuration.class, "sconf");
    
    FileInputStream fis = null;
    try
    {
      fis = new FileInputStream(f);

      Configuration c = (Configuration) x.fromXML(fis);

      fis.close();

      c.decodePasswords();

      return c;
    } catch (Exception ex) {
      ex.printStackTrace();
      return null;
    }
  }

  public boolean write(File f)
  {
    if(f == null)
      return false;

    XStream x = new XStream();
    x.omitField(Configuration.class, "econf");
    x.omitField(Configuration.class, "conf");
    x.omitField(Configuration.class, "sconf");

    FileOutputStream fos = null;
    try
    {
      fos = new FileOutputStream(f);

      this.encodePasswords();

      x.toXML(this, fos);
      
      fos.close();
    } catch (Exception ex) {
      ex.printStackTrace();
      return false;
    }
    return true;
  }
  
  private void encodePasswords()
  {
    if(users == null || this.numUsers() <= 0)
      return;
    
    BASE64Encoder enc = new BASE64Encoder();
    
    Iterator<String> itUsers = users.keySet().iterator();
    while(itUsers.hasNext())
    {
      String user = itUsers.next();
      String passwd = users.get(user);
      passwd = enc.encode(passwd.getBytes());
      users.put(user, passwd);
    }
  }
  
  private void decodePasswords()
  {
    if(users == null || this.numUsers() <= 0)
      return;
    
    BASE64Decoder dec = new BASE64Decoder();
    
    Iterator<String> itUsers = users.keySet().iterator();
    while(itUsers.hasNext())
    {
      String user = itUsers.next();
      String passwd = users.get(user);
      try
      {
        passwd = new String(dec.decodeBuffer(passwd));
        users.put(user, passwd);
      } catch (IOException ex) { System.out.println( "ERROR DECODING PASSWORDS: "+ user ); }
    }
  }

  public int getPort()
  {
    return port;
  }

  public void setPort(int port)
  {
    if(port <= 0) return;
    this.port = port;
  }

  public String getHost()
  {
    return host;
  }

  public void setHost(String host)
  {
    if(host == null || host.equals(""))
        return;

    this.host = host;
  }

  public String getDBFile()
  {
    return dbFile;
  }

  public void setDBFile(String filename)
  {
    if(filename == null || filename.equals(""))
        return;

    this.dbFile = filename;
  }

  public EmbeddedConfiguration getEmbeddedConfiguration()
  {
    return econf;
  }

  public ClientConfiguration getClientConfiguration()
  {
    return conf;
  }

  public ServerConfiguration getServerConfiguration()
  {
    return sconf;
  }

  public void setServerConfiguration(ServerConfiguration conf)
  {
    sconf = conf;
  }

  public void setClientConfiguration(ClientConfiguration conf)
  {
    this.conf = conf;
  }

  public void setEmbeddedConfiguration(EmbeddedConfiguration conf)
  {
    this.econf = conf;
  }

  public ObjectContainer startDB()
  {
    db = Db4oEmbedded.openFile(econf, dbFile);
    return db;
  }

  public ObjectContainer startClient(String user, String password)
  {
    db = Db4oClientServer.openClient(conf, host, port, user, password);
    return db;
  }

  public ObjectServer startServer()
  {
    ObjectServer server = Db4oClientServer.openServer(sconf, dbFile, port);
    Iterator<String> itUsers = users.keySet().iterator();
    while(itUsers.hasNext()) {
      String user = itUsers.next();
      server.grantAccess(user, users.get(user));
    }
    db = server.openClient();
    return server;
  }


  public static void main(String[] args)
  {
    Configuration c = new Configuration();
    c.setDBFile("T:/Java/powercash.db");
    c.setPort(DEFAULT_PORT);
    c.setHost("localhost");
    c.addUser("juno", "1234");
    File f = new File("T:/Java/powercash-conf.xml");
    c.write(f);
    c = Configuration.load(f);
    System.out.println( c.getPassword("juno") );
  }

}
